<template>
  <div class="upload-excel-container">
    <el-row class="mb-3">
      <el-col :span="6" :push="3" v-if="checkDataAllNum != 0" class="tx-right">
        <el-card class="box-card">
          <div slot="header" class="clearfix">
            <span>查重详情</span>
          </div>

          <el-col :span="12">
            <el-row class="text item">
              <el-col :span="12">{{ '总数据' }}</el-col>
              <el-col :span="12">
                <el-tag size="mini">{{ checkDataAllNum }}</el-tag>
              </el-col>
            </el-row>
            <el-row class="text item">
              <el-col :span="12">{{ '非法数据' }}</el-col>
              <el-col :span="12">
                <el-tag size="mini" type="danger">{{ illegalRowNum }}</el-tag>
              </el-col>
            </el-row>
            <el-row class="text item">
              <el-col :span="12">{{ '重复数据' }}</el-col>
              <el-col :span="12">
                <el-tag size="mini" type="warning">{{ checkDataNum }}</el-tag>
              </el-col>
            </el-row>
            <el-row class="text item">
              <el-col :span="12">{{ '重复比例' }}</el-col>
              <el-col :span="12">
                <el-tag
                  size="mini"
                  type="info"
                >{{ ((checkDataNum / checkDataAllNum) * 100).toFixed(0) + "%" }}</el-tag>
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="12" class="tx-center">
            <el-popover
              ref="popover1"
              placement="top-start"
              title="查重数据进度"
              width="200"
              trigger="hover"
              :content="checkDataNum + '/' + checkDataAllNum + ' (已查的重复数据/需查重总数据)'"
            ></el-popover>
            <el-progress
              v-popover:popover1
              v-if="checkPercentage != 100"
              type="circle"
              :percentage="checkPercentage"
            ></el-progress>
            <el-progress v-popover:popover1 v-else type="circle" :percentage="100" status="success"></el-progress>
          </el-col>
        </el-card>
      </el-col>
      <el-col :span="12" :push="checkDataAllNum != 0 ? 5 : 8" class="el-row--flex">
        <uploadExcel-component :on-success="handleSuccess" :before-upload="beforeUpload"></uploadExcel-component>
      </el-col>
    </el-row>
    <el-row v-if="checking" class="mb-3">
      <el-button type="warning" @click="cancelUpload">取消上传</el-button>
    </el-row>

    <vxe-grid
      ref="xGrid"
      border
      resizable
      keep-source
      height="580"
      align="center"
      :row-class-name="getRowClassName"
      :loading="loading"
      :data="tableData"
      :keyboard-config="keyConfig"
      :edit-config="{trigger: 'manual', mode: 'row', autoClear: false,showStatus: true, icon: 'fa fa-file-text-o'}"
      :edit-rules="validRules"
    >
      <vxe-table-column type="seq" width="70">
        <template v-slot:header="{ column }">
          <span>序号</span>
          <i class="el-icon-question" />
        </template>
      </vxe-table-column>
      <vxe-table-column field="village" title="所属村" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-cascader
            v-model="scope.row.village"
            :options="villageCascader"
            :show-all-levels="false"
            @input="$refs.xGrid.updateStatus(scope)"
            @change="villageChange(scope.row)"
          />
        </template>
        <template
          v-slot="{ row }"
        >{{ villageCascader.filter(town => town.id == row.village[0]).length == 1 ? villageCascader.filter(town => town.id == row.village[0])[0].village.filter(village => village.id == row.village[1])[0].name : "错误输入" }}</template>
      </vxe-table-column>
      <vxe-table-column field="group" title="所属组" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-select v-model="scope.row.group" clearable @change="$refs.xGrid.updateStatus(scope)">
            <el-option
              v-for="item in scope.row.groupAtt"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            />
          </el-select>
        </template>
        <template v-slot="{ row }">
          {{ (row.group == "错误输入" | !row.group) ? row.group : row.groupAtt && row.groupAtt.filter(item => item.id == row.group)[0] ? row.groupAtt.filter(item => item.id == row.group)[0].name : row.group }}
          <!-- {{ row.groupAtt }} -->
        </template>
      </vxe-table-column>
      <vxe-table-column field="type" title="资金类型" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-select v-model="scope.row.type" @change="$refs.xGrid.updateStatus(scope)">
            <el-option
              v-for="item in typeList"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </template>
        <template v-slot="{ row }">{{ row.type == "错误输入" ? row.type : typeList[row.type].label }}</template>
      </vxe-table-column>

      <vxe-table-column field="time" title="时间" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-date-picker
            v-model="scope.row.time"
            type="date"
            value-format="yyyy-MM-dd"
            placeholder="选择日期"
          />
        </template>
        <template v-slot="{ row }">{{ row.time }}</template>
      </vxe-table-column>

      <vxe-table-column field="input" title="收入" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-input v-model="scope.row.input" @input="$refs.xGrid.updateStatus(scope)" />
        </template>
        <template v-slot="{ row }">{{ row.input }}</template>
      </vxe-table-column>
      <vxe-table-column field="output" title="支出" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-input v-model="scope.row.output" @input="$refs.xGrid.updateStatus(scope)" />
        </template>
        <template v-slot="{ row }">{{ row.output }}</template>
      </vxe-table-column>
      <vxe-table-column field="cause" title="事由" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-input v-model="scope.row.cause" @input="$refs.xGrid.updateStatus(scope)" />
        </template>
        <template v-slot="{ row }">{{ row.cause }}</template>
      </vxe-table-column>
      <vxe-table-column field="remarks" title="备注" :edit-render="{}">
        <template v-slot:edit="scope">
          <el-input v-model="scope.row.remarks" @input="$refs.xGrid.updateStatus(scope)" />
        </template>
        <template v-slot="{ row }">{{ row.remarks }}</template>
      </vxe-table-column>

      <vxe-table-column title="操作" width="160">
        <template v-slot="scope">
          <template v-if="$refs.xGrid.isActiveByRow(scope.row)">
            <vxe-button
              v-if="!checking"
              icon="fa fa-save el-icon-document"
              status="primary"
              title="保存"
              circle
              @click="saveRowEvent(scope.row)"
            />
          </template>
          <template>
            <vxe-button
              v-if="!checking"
              icon="fa fa-edit el-icon-edit-outline"
              title="编辑"
              circle
              @click="editRowEvent(scope.row)"
            />
          </template>
          <vxe-button
            v-if="!checking"
            icon="fa fa-trash el-icon-delete"
            title="删除"
            circle
            @click="removeRowEvent(scope.row, scope.seq - 1)"
          />
        </template>
      </vxe-table-column>
    </vxe-grid>

    <vxe-toolbar>
      <template v-slot:buttons>
        <el-button v-if="illegalRowNum == 0 && !checking" type="primary" @click="uploadData">
          上传到服务器
          <i class="el-icon-upload el-icon--right" />
        </el-button>
        <el-button v-if="illegalRowNum == 0 && !checking" type="warning" @click="upload">
          已经检查,确认上传数据
          <i class="el-icon-upload el-icon--right" />
        </el-button>
      </template>
    </vxe-toolbar>
  </div>
</template>

<script>
import UploadExcelComponent from "@/components/UploadExcel/index.vue";
import { mapGetters } from "vuex";

export default {
  name: "UploadExcel",
  components: {
    UploadExcelComponent,
  },
  data() {
    return {
      loading: false,
      keyConfig: {
        isArrow: true,
        isDel: true,
        isEnter: true,
        isTab: true,
        isEdit: true,
      },
      villageAtt: [],
      groupAtt: [],
      tableData: [],
      tableHeader: [],
      noError: false,
      validConfig: {
        // autoPos: true,
        // maxWidth: 2,
      },
      typeList: [
        {
          label: "现金收支",
          value: 0,
        },
        {
          label: "银行收支",
          value: 1,
        },
      ],
      rowStatus: [],
      validRules: {
        village: [
          { required: true, message: "请选择所属村", trigger: "change" },
        ],
        type: [
          { required: true, message: "请选择资金类型", trigger: "change" },
        ],
        time: [
          { required: true, message: "请选择资金日期", trigger: "change" },
        ],
        input: [
          {
            required: true,
            message: "请输入收入金额(单位为元)",
            trigger: "blur",
          },
        ],
        output: [
          {
            required: true,
            message: "请输入支出金额(单位为元)",
            trigger: "blur",
          },
        ],
        cause: [{ required: true, message: "请输入事由内容", trigger: "blur" }],
        remarks: [
          {
            required: false,
            message: "请输入备注内容",
            trigger: "blur",
          },
        ],
      },
      nationAtt: [],
      villageCascader: [],
      cacheGroup: {},
      config: {
        exclude: ["relatedDocuments", "id"],

        village: {
          index: 0,
          alias: "所属村",
          map: (village) => village,
        },
        group: {
          index: 0,
          alias: "所属组",
          // map: () => {}
          map: (group) => group,
        },
        type: {
          index: 0,
          alias: "类型",
          map: (sex, row) => {
            if (sex && (sex.trim() == "现金收支" || sex.trim() == "银行收支")) {
              return sex.trim() == "现金收支" ? 0 : 1;
            } else {
              row._type = 0;
              return "错误输入";
            }
          },
        },
        time: {
          index: 5,
          alias: "时间",
          // map: () => {}
        },
        input: {
          index: 6,
          alias: "收入",
          map: (input, row) => this.numChangeDecimalOrFail(input, row),
        },
        output: {
          index: 7,
          alias: "支出",
          map: (output, row) => this.numChangeDecimalOrFail(output, row),
        },
        cause: {
          index: 8,
          alias: "事由",
          // map: () => {}
        },
        remarks: {
          index: 9,
          alias: "备注",
          // map: () => {}
        },
        createdAt: {
          index: 0,
          alias: "创建时间",
          map: (str) => this.XEUtils.toDateString(str),
        },
      },

      checkPercentage: 0,
      checking: true,
      checkDataNum: 0,
      checkDataAllNum: 0,
      illegalRowNum: 0,
    };
  },
  watch: {
    checking(val) {
      if (!this.checking) {
        if (this.checkDataNum == 0) {
          this.$notify.success({
            title: "查重结果",
            message: "无重复内容",
          });
        } else {
          this.$notify({
            type: "warning",
            title: `查重结果  时间 ${this.XEUtils.toDateString(
              Date.now(),
              "HH:mm MM-dd"
            )}`,
            message:
              "检查重复内容, 已置顶重复项(也可能不是重复项), 请妥善处理相关项。",
            duration: 0,
          });
        }
      }
    },
    tableData: {
      handler(newValue, oldValue) {
        if (Array.isArray(newValue)) {
          this.checkDataAllNum = newValue.length;
          this.illegalRowNum = newValue.filter((row) => row._type == 0).length;
          this.checkDataNum = newValue.filter((row) => row._type == 1).length;
          console.log(
            this.checkDataAllNum,
            this.illegalRowNum,
            this.checkDataNum
          );
        }
      },
      deep: true,
      immediate: true,
    },
  },
  computed: {
    ...mapGetters({
      user: "user/info",
    }),
  },
  created() {
    this.$nextTick(() => {
      this.init();
    });
  },
  methods: {
    numChangeDecimalOrFail(num, row) {
      let str = String(num);
      let strAtt = str.split(".");
      if (strAtt.length == 2) {
        if (strAtt[1].length == 0) strAtt[1] = "00";
        if (strAtt[1].length == 1) strAtt[1] = strAtt[1] + "0";
        if (strAtt[1].length > 2) strAtt[1] = strAtt[1].splice(0, 2);
        return strAtt.join(".");
      } else if (strAtt.length == 1) {
        strAtt[0] = strAtt[0] + ".00";
        return strAtt.join(".");
      } else {
        row._type = 0
        return "错误输入";
      }
    },
    async init() {
      const res = await this.$http.get(`town?join=village&join=village.group`);

      res.data.forEach((town) => {
        town.label = town.name;
        town.value = town.id;
        town.children = town.village;
        town.children.forEach((village) => {
          village.label = village.name;
          village.value = village.id;
        });
      });

      this.villageCascader = res.data;
      // this.setSelectItem()
      console.log(this.villageCascader);
    },
    setSelectItem() {
      if (this.user.level < 1) {
      } else if (this.user.level == 1) {
        //区级
        this.villageCascader.forEach((area) => {
          if (area.id == this.user.area.id) {
            area.disabled = false;
          } else {
            area.disabled = true;
            if (area.town.length > 0) {
              area.town.forEach((town) => {
                town.disabled = true;
              });
            }
          }
        });
      } else if (this.user.level == 2) {
        //镇级
        this.villageCascader.forEach((area) => {
          if (area.id == this.user.area.id) {
            area.disabled = false;
            if (area.town.length > 0) {
              area.town.forEach((town) => {
                if (town.id == this.user.town.id) {
                  town.disabled = false;
                } else {
                  town.disabled = true;
                }
              });
            }
          } else {
            area.disabled = true;
            if (area.town.length > 0) {
              area.town.forEach((town) => {
                town.disabled = true;
              });
            }
          }
        });
      } else if (this.user.level == 3) {
        //村级
        // this.change([this.user.village.id])
      }
    },
    beforeUpload(file) {
      return true;
    },
    async handleSuccess({ results, header }) {
      debugger
      results.forEach((row) => (row._type = 2));
      await this.beforeGetData(results, header);
      this.fullValidEvent(results);
      this.checkPercentage = 0;
      let num = 0;
      results.forEach(async (row, index) => {
        let flag = await this.checkDuplicate(row, index);
        this.checkPercentage = parseFloat(
          ((++num / results.length) * 100).toFixed(2)
        );
        this.$forceUpdate();
        console.log(num, results.length);
        if (num >= results.length - 1) {
          this.checking = false;
          results.sort((a, b) => a._type - b._type);
        }
      });
      this.tableData = results;
      this.tableHeader = header;
    },
    getGroup(villageAtt) {
      if (!villageAtt) {
        return [];
      }
      let town = this.villageCascader.filter(
        (town) => town.id == villageAtt[0]
      );
      let village =
        town.length > 0 &&
        town[0].village.filter((village) => village.id == villageAtt[1]);
      console.log(this.villageCascader, town, village);
      if (village.length > 0) {
        return village[0].group;
      } else {
        return [];
      }
    },
    async beforeGetData(results, header) {
      results.shift();
      //删除说明

      results.forEach((row) => {
        let village = this.findVillage(row.village, this.villageCascader);
        if (village.length == 2) {
          row.village = village;
        } else {
          row._type = 0;
          row.village = "错误输入";
        }
      });

      results.forEach((row) => {
        for (const key in row) {
          if (row.hasOwnProperty(key) && this.config[key]) {
            row[key] = this.config[key].map
              ? this.config[key].map(row[key], row)
              : row[key];
            if (key == "group" && row["village"].length == 2) {
              let groupAtt = this.getGroup(row["village"]);
              Object.assign(row, { groupAtt });
              this.$forceUpdate();
              if (row.groupAtt) {
                let group = row.groupAtt.filter(
                  (group) => group.name == row.group
                )[0];
                if (!group || group.length == 0) {
                  row._type = 0;
                  row.group = "错误输入";
                } else {
                  row.group = group.id;
                }
              } else {
                // row.groupAtt = []
              }
            } else {
              // row.groupAtt = []
            }
          }
        }
      });
      // this.fullValidEvent(results)

      console.log(results);
    },
    findVillage(name, villageCascader) {
      if (!name) {
        return [];
      }
      let areaToVillage = [];
      villageCascader.forEach((town) => {
        let att = [];
        att.push(town.id);
        town.children.forEach((village, index) => {
          if (typeof name == "string" && village.name == name.trim()) {
            att.push(village.id);
            areaToVillage = att;
          }
        });
      });
      return areaToVillage;
    },
    async villageChange(row) {
      let groupAtt = this.getGroup(row.village);
      row.group = "";
      Object.assign(row, { groupAtt });
      this.$forceUpdate();
    },
    async checkDuplicate(row) {
      if (row._type != 0) {
        const res = await this.$http.get(
          `funds?s={"input": "${row.input}", "output": "${row.output}","time": "${row.time}", "village.id":${row.village[1]}}&join=village`
        );
        row.checkDuplicate = res.data;
        if (res.data.length > 0 && res.data.filter(data => data.cause == row.cause).length > 0) {
          this.checkDataNum++;
          row._type = 1;
          return true;
        } else {
          return false;
        }
      }
    },
    editRowEvent(row) {
      this.$refs.xGrid.setActiveRow(row);
    },
    async saveRowEvent(row) {
      let previousType = row._type;
      console.log(row);
      this.$refs.xGrid.validate(row, async (errMap) => {
        console.log(errMap);
        if (errMap) {
          row._type = 0;
          if (previousType != 0) {
            this.illegalRowNum++;
          } else if (previousType == 1) {
            this.checkDataNum--;
          }
        } else {
          let flag = await this.checkDuplicate(row);
          console.log(flag);
          if (flag) {
            row._type = 1;
            if (previousType != 1) {
              this.checkDataNum++;
            } else if (previousType == 0) {
              this.illegalRowNum--;
            }
          } else {
            row._type = 2;
            if (previousType == 1) {
              this.checkDataNum--;
            } else if (previousType == 0) {
              this.illegalRowNum--;
            }
          }
        }

        this.tableData.sort((a, b) => {
          console.log(a._type, b._type);
          return a._type - b._type;
        });
      });
      this.$refs.xGrid.clearActived().then(() => {
        setTimeout(() => {
          this.$message({
            message: "保存成功！",
            type: "success",
          });
        }, 300);
      });
    },
    removeRowEvent(row, index) {
      this.$confirm("此操作将删除该数据, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // this.tableData.
          console.log(row);
          this.$refs.xGrid.remove(row);
          this.tableData.splice(index, 1);
          this.$message({
            type: "success",
            message: "删除成功!",
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
    },
    async fullValidEvent(results) {
      results.sort((a, b) => a._type - b._type);
      this.$refs.xGrid.fullValidate(results, (errMap) => {
        if (errMap) {
          let msgList = [];
          Object.values(errMap).forEach((errList) => {
            errList.forEach((params) => {
              let { rowIndex, column, rules } = params;
              rules.forEach((rule) => {
                results[
                  rowIndex
                ]._message = `${column.title} 初步校验错误：${rule.message} \n`;
                results[rowIndex]._type = 0;
              });
            });
          });

          //排序
          results.sort((a, b) => a._type - b._type);

          let illegalRows = results.filter((item) => item._type == 0);

          this.illegalRowNum = illegalRows.length;

          illegalRows.forEach((item, index) =>
            msgList.push(`第 ${index + 1} 行 ${item._message}`)
          );

          this.$notify({
            dangerouslyUseHTMLString: true,
            type: "error",
            duration: 0,
            title: `错误信息提示 时间 ${this.XEUtils.toDateString(
              Date.now(),
              "HH:mm MM-dd"
            )}`,
            message: `<div class="red" style="max-height: 400px;overflow: auto;">
                        ${msgList.map((msg) => {
                          return `<div>${msg}</div>`;
                        })}
                      </div>`,
          });
        } else {
          if (results.filter((row) => row._type == 0).length == 0) {
            this.noError = true;
            // debugger
            this.$message.success(`校验成功！`);
          }
        }
      });
    },
    getRowClassName({
      row,
      rowIndex,
      $rowIndex,
      column,
      columnIndex,
      $columnIndex,
    }) {
      if (row._type == 0) {
        // 数据错误
        return "error-row";
      } else if (row._type == 1) {
        // 数据可能重复
        return "warning-row";
      } else if (row._type == 2) {
        // 数据正常
        return "info-row";
      }
    },
    beforeSubmit(data) {
      let errorMessage = [];
      data.forEach((row, index) => {
        if (row.checkDuplicate.length > 0) {
          errorMessage.push(
            `第${index + 1}条数据, 可能存在重复提交问题, 也可能是正确的`
          );
          row._type = 1;
        }
      });
      if (errorMessage.length > 0) {
        this.$notify({
          dangerouslyUseHTMLString: true,
          type: "warning",
          duration: 0,
          title: `错误信息提示 时间 ${this.XEUtils.toDateString(
            Date.now(),
            "HH:mm MM-dd"
          )}`,
          message: `<div class="yellow" style="max-height: 400px;overflow: auto;">
                        ${errorMessage.map((msg) => {
                          return `<div>${msg}</div>`;
                        })}
                      </div>`,
        });
      } else {
        return true;
      }
    },
    async uploadData() {
      console.log(this.tableData);
      let check = this.beforeSubmit(this.tableData);
      if (check) {
        this.upload();
      } else {
        this.$alert(
          "存在可能重复的数据, 请修改或者使用另一种提交方式",
          "提交数据",
          {
            confirmButtonText: "确定",
            callback: (action) => {
              this.$message({
                type: "info",
                message: `修改可能重复的数据 或者 用 [已经检查,确认上传数据] 提交数据`,
              });
            },
          }
        );
      }
    },
    uploaPidpe(data) {
      const bulkData = JSON.parse(JSON.stringify(data));
      bulkData.forEach((item) => {
        item.village = item.village[1];

        item.input = item.input.toString();
        item.output = item.output.toString();
        item.cause = item.cause.toString();
        item.remarks ? (item.remarks = item.remarks.toString()) : "";

        if (!item.group) delete item.group;
        delete item.createdAt;
        delete item.groupAtt;
      });
      console.log(bulkData);
      return bulkData;
    },
    async upload() {
      this.$confirm(
        "此操作将强制提交数据(中间可能包含重复项), 是否继续?",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(async () => {
          let data = this.uploaPidpe(this.tableData);
          this.loading = true;
          try {
            const res = await this.$http.post(`funds/bulk`, {
              bulk: data,
            });
            if (res.status == 201) {
              this.$notify({
                type: "success",
                title: `上传成功  时间 ${this.XEUtils.toDateString(
                  Date.now(),
                  "HH:mm MM-dd"
                )}`,
                message: `上传成功, 共计上传 ${data.length} 条相关数据`,
                duration: 0,
              });
              this.$emit("close", true);
            } else {
              this.$message.success(`${res.data.message}`);
              this.loading = false;
            }
          } catch (error) {
            this.$message.success(`${res.data.message}`);
          }
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消",
          });
        });
    },
    cancelUpload() {
      this.$confirm(
        "如果数据存在大量重复, 或者之前上传过, 建议你取消上传数据",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(() => {
          this.$message({
            type: "success",
            message: "终止上传操作成功!",
          });
          this.$http.cancel();
          location.reload();
          this.$emit("close", true);
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消终止上传操作",
          });
        });
    },
  },
};
</script>

<style lang="css">
.warning-row {
  background: oldlace !important;
}

.info-row {
  background: #f0f9eb !important;
}

.error-row {
  background: #f3c8c8 !important;
}

.mb-3 {
  margin-bottom: 30px;
}

.vxe-input--panel.type--date,
.vxe-input--panel.type--month,
.vxe-input--panel.type--week,
.vxe-input--panel.type--year {
  z-index: 9998 !important;
}
.vxe-select--panel {
  z-index: 9997 !important;
}
</style>
